package org.hive.vmware.server;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.hive.vmware.client.model.HostTreeFolder;
import org.hive.vmware.client.model.VmCenterServerTreeFolder;
import org.hive.vmware.client.model.VmCenterServerVO;
import org.hive.vmware.client.model.VmGroupVO;
import org.hive.vmware.client.model.VmGroupingVO;
import org.hive.vmware.client.model.VmVO;
import org.hive.vmware.client.service.VmwareService;
import org.hive.vmware.model.VmCenterServer;
import org.hive.vmware.model.VmGroupBee;
import org.hive.vmware.repository.VmwareRepository;
import org.hive.vmware.translator.VmCenterServerModelVOTranslator;
import org.hive.vmware.translator.VmGroupModelVOTranslator;

import ca.intelliware.commons.virtualization.CenterServer;
import ca.intelliware.commons.virtualization.DataCenter;
import ca.intelliware.commons.virtualization.Host;
import ca.intelliware.commons.virtualization.VMachine;
import ca.intelliware.commons.virtualization.vmware.VmwareVmExplorer;

import com.extjs.gxt.ui.client.data.BaseTreeModel;
import com.extjs.gxt.ui.client.data.ModelData;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * The server side implementation of the RPC service.
 */
public class GwtVmwareServiceImpl extends RemoteServiceServlet implements VmwareService {

	private static final long serialVersionUID = 1L;

	@Override
	public List<VmCenterServerVO> loadVmCenterServers() {
		VmwareRepository vmwareRepository = new VmwareRepository();
		List<VmCenterServer> centerServers = vmwareRepository.findAllVmCenterServers();
		
		VmCenterServerModelVOTranslator modelTranslator = new VmCenterServerModelVOTranslator();
		ArrayList<VmCenterServerVO> vmCenterServerVOs = new ArrayList<VmCenterServerVO>();
		for (VmCenterServer vmCenterServer : centerServers) {
			VmCenterServerVO vmCenterServerVO = modelTranslator.translateVmCenterServerToVO(vmCenterServer);
			if (vmCenterServerVO != null) {
				vmCenterServerVOs.add(vmCenterServerVO);
			}			
		}
		return vmCenterServerVOs;
	}

	@Override
	public boolean saveVmCenterServers(List<VmCenterServerVO> vmCenterServerVOs) {
	
		VmCenterServerModelVOTranslator modelTranslator = new VmCenterServerModelVOTranslator();
		ArrayList<VmCenterServer> vmCenterServers = new ArrayList<VmCenterServer>();
		for (VmCenterServerVO vmCenterServerVO : vmCenterServerVOs) {
			VmCenterServer vmCenterServer = modelTranslator.translateVmCenterServerVOToModel(vmCenterServerVO);
			if (vmCenterServer != null) {
				vmCenterServers.add(vmCenterServer);
			}
		}
		
		VmwareRepository vmwareRepository = new VmwareRepository();
		return vmwareRepository.saveAllVmCenterServers(vmCenterServers);
	}

	@Override
	public VmCenterServerTreeFolder loadVmCenterFolder() {
		VmCenterServerTreeFolder rootFolder = new VmCenterServerTreeFolder("root");
		List<VmCenterServerTreeFolder> treeFolders = new ArrayList<VmCenterServerTreeFolder>();
		try {
			VmwareVmExplorer vmExplorer = vmExplorer();
			List<VmCenterServerVO> vmCenterServers = loadVmCenterServers();
			for (VmCenterServerVO vmCenterServer : vmCenterServers) {
				HostTreeFolder[] hostFolders = new HostTreeFolder[0];
				if (Boolean.getBoolean("dev")) {
					hostFolders = new DummyData().createDummyHosts(vmCenterServer.getUrl(), this);
				} else {
					DataCenter dataCenter = findDataCenter(vmCenterServer, vmExplorer);
					if (dataCenter != null) {
						hostFolders = extraInfoFromHosts(vmCenterServer, dataCenter);
					}
				}
				VmCenterServerTreeFolder vmCenterServerTreeFolder 
						= new VmCenterServerTreeFolder(vmCenterServer.getUrl(),	hostFolders);
				treeFolders.add(vmCenterServerTreeFolder);
			}
		} catch (Exception e) {
			rootFolder.setLoadError(true);
			e.printStackTrace();
		}
		
		for (VmCenterServerTreeFolder folder : treeFolders) {
			rootFolder.add(folder);
		}
		
		return rootFolder;
	}
	
	VmwareVmExplorer vmExplorer() {
		return VmwareVmExplorer.getInstance();
	}
	
	@SuppressWarnings("unused")
	List<VmVO> loadVms() {
		List<VmVO> vms = new ArrayList<VmVO>();
		VmCenterServerTreeFolder vmCenterServerRoot = loadVmCenterFolder();
		List<ModelData> centerServers = vmCenterServerRoot.getChildren();
		for (ModelData serverCenter : centerServers) {
			VmCenterServerTreeFolder centerTree = (VmCenterServerTreeFolder)serverCenter;
			List<ModelData> hostTree = centerTree.getChildren();
			for (ModelData hostModel : hostTree) {
				HostTreeFolder host = (HostTreeFolder)hostModel;
				List<ModelData> hostVms = host.getChildren();
				for (ModelData vm : hostVms) {
					vms.add((VmVO)vm);
				}
			}
		}
		return vms;
	}
	
	
	DataCenter findDataCenter(VmCenterServerVO vmCenterServerVO, VmwareVmExplorer vmExplorer) throws Exception {
		
		vmExplorer.addNewCenterServer(vmCenterServerVO.getUrl(), vmCenterServerVO.getUserId(), vmCenterServerVO.getPassword());
		CenterServer centerServer = vmExplorer.centerServer(new URL(vmCenterServerVO.getUrl()));
		List<DataCenter> dataCenters = centerServer.dataCenters();
		if (dataCenters.size() > 0) {
			return dataCenters.get(0);
		} else {
			return null;
		}
	}
	
	private HostTreeFolder[] extraInfoFromHosts(VmCenterServerVO vmCenterServer, DataCenter dataCenter) throws IOException { 
		List<Host> hosts = dataCenter.hosts();
		HostTreeFolder[] folders = new HostTreeFolder[hosts.size()];
		
		for (int i = 0; i < folders.length; i++) {
			Host host = hosts.get(i);
			folders[i] = new HostTreeFolder(host.getId(), extraInfoFromVMs(vmCenterServer, dataCenter, host));
		}
		return folders;
		
	}
	
	private BaseTreeModel[] extraInfoFromVMs(VmCenterServerVO vmCenterServer, DataCenter dataCenter, Host host) throws IOException {
		Collection<VMachine> virtualMachines = host.virtualMachines();
		VmVO[] vmVOs = new VmVO[virtualMachines.size()];
		VMachine[] vms = virtualMachines.toArray(new VMachine[]{});
		for (int i = 0; i < vmVOs.length; i++) {
			VmVO vm = new VmVO();
			vm.setName(vms[i].getId());
			vm.setHost(host.getId());
			vm.setCenterServer(vmCenterServer.getUrl());
			vm.setDataCenter(dataCenter.getId());
			vm.setDescription(vm.getName() + "/" + vm.getHost());
			vmVOs[i] = vm;
		}
		return vmVOs;
	}

	
	List<VmGroupVO> loadVmGroups() {
		VmwareRepository vmwareRepository = new VmwareRepository();
		List<VmGroupBee> vmGroups = vmwareRepository.findAllVmGroups();
		VmGroupModelVOTranslator vmGroupModelTranslator = new VmGroupModelVOTranslator();
		return vmGroupModelTranslator.translateVmGroupsToVO(vmGroups);
	}


	boolean saveVmGroups(List<VmGroupVO> vmGroups) {
		VmwareRepository vmwareRepository = new VmwareRepository();
		VmGroupModelVOTranslator vmGroupModelTranslator = new VmGroupModelVOTranslator();			
		return vmwareRepository.saveAllVmGroups(
				vmGroupModelTranslator.translateVmGroupsToModel(vmGroups));
	}

	@Override
	public VmGroupingVO loadVmGrouping() {
		List<VmVO> vms = loadVms();
		List<VmGroupVO> vmGroups = loadVmGroups();
		for (VmGroupVO vmGroupVO : vmGroups) {
			List<VmVO> groupedVms = vmGroupVO.getVms();
			for (VmVO vmVO : groupedVms) {
				vms.remove(vmVO);
			}
		}
		VmGroupingVO groupingVO = new VmGroupingVO();
		groupingVO.setGroupVOs(vmGroups);
		groupingVO.setUngroupedVOs(vms);
		return groupingVO;
	}

	@Override
	public boolean saveVmGrouping(VmGroupingVO groupingVO) {
		return saveVmGroups(groupingVO.getGroupVOs());
	}

	@Override
	public boolean revertVms(List<VmVO> vms) {
		if (Boolean.getBoolean("dev")) {
	
		} else {
			VmwareVmExplorer vmExplorer = vmExplorer();
			List<VmCenterServerVO> centerServers = loadVmCenterServers();
			for (VmCenterServerVO vmCenterServerVO : centerServers) {
				try {
					vmExplorer.addNewCenterServer(vmCenterServerVO.getUrl(), 
							vmCenterServerVO.getUserId(), vmCenterServerVO.getPassword());
				} catch (IOException e) {
					// how to handle this?
				}
			}
			for (VmVO vmVO : vms) {
				try {
					CenterServer centerServer = vmExplorer.centerServer(new URL(vmVO.getCenterServer()));
					List<DataCenter> dataCenters = centerServer.dataCenters();
					for (DataCenter dataCenter : dataCenters) {
						Host host = dataCenter.host(vmVO.getHost());
						if (host != null) {
							VMachine virtualMachine = host.virtualMachine(vmVO.getName());
							virtualMachine.revertToLastSnapshot();
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		return true;
	}

}
